#include "sqliteDataBase.h"
#include <iostream>
#include <string>


// 构造函数
// 初始化列表在进入构造函数体之前就会对成员变量进行初始化
// 因此在进入构造函数体时，成员变量已经被赋予了指定的初始值或调用了指定的构造函数
// 这种机制相当于提前完成成员变量的构造，而不是进入构造函数体后再赋值或修改成员变量的内容
// 初始化列表初始化成员的效率更高，特别是对于非基础数据类型（如类、结构体）
SqliteDataBase::SqliteDataBase() : m_db(nullptr) // 初始化列表
{

}

// 析构函数
SqliteDataBase::~SqliteDataBase()
{

}

// 连接数据库
bool SqliteDataBase::connectDB(const std::string &connStr)
{
    // 打开数据库
    int ret = sqlite3_open(connStr.c_str(), &m_db);
    if (ret != SQLITE_OK)
    {
        std::cout << "sqlite3 open error" << std::endl;
        exit(-1);
    }
    return true;
}

// 执行Sql执行语句(exec)
bool SqliteDataBase::executeSql(const std::string &sql)
{
    // 执行sql语句
    int ret = sqlite3_exec(m_db, sql.c_str(), NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        std::cout << "sqlite exec error." << std::endl;
        return false;
    }

    return true;
}

// 执行Sql查询语句(select)
QueryResult SqliteDataBase::querySql(const std::string &sql)
{
    char **result = NULL;
    int rows = 0; // 行（数据的行数，不包括列名那一行）
    int columns = 0; // 列

    QueryResult res;
    // 用于执行 SQL 查询并将查询结果以二维数组的形式存储在内存中
    // 它适合处理较小的查询结果，因为它会将所有数据加载到内存中
    // 但对于大型数据集，建议使用更灵活的 sqlite3_prepare_v2 等接口
    int ret = sqlite3_get_table(m_db, sql.c_str(), &result, &rows, &columns, NULL);
    // m_db：数据库句柄（指向打开的数据库连接）。
    // sql.c_str()：包含 SQL 查询语句的字符串，用于获取 userInfo 表的全部数据。
    // &result：指向 char** 类型的指针变量，sqlite3_get_table 会为该指针分配内存，并将查询结果填充到这个二维数组中。
    // &rows 和 &columns：用于获取查询结果的行数和列数，分别包含查询的数据行数和每行的列数。
    // NULL：这里是 errmsg 参数，用于存储查询出错时的错误消息，传入 NULL 表示忽略错误消息
    if (ret != SQLITE_OK)
    {
        std::cout << "sqlite3 get table error." << sqlite3_errmsg(m_db) << std::endl; // sqlite3_errmsg()可以打印错误信息
        return res;
    }

    // 列名
    for (int idx = 0; idx < columns; idx++)
    {
        res.columnName.push_back(result[idx]);
    }
    
    // 数据
    for (int row = 1; row <= rows; row++) // 这里的rows不包括列名的那一行！
    {
        std::vector<std::string> tmp;
        for (int col = 0; col < columns; col++)
        {
            tmp.push_back(result[row * columns + col]);
        }
        res.rows.push_back(tmp);
    }

    return res;
}

// 关闭数据库连接
void SqliteDataBase::close()
{
    sqlite3_close(m_db);
}
